﻿using System;
using System.Linq;
using System.Net;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Prism.Events;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Unity;
using DXTools.UI.Core;
using DXTools.UI.Modules.Statistics.Views;
using DXTools.UI.Core.Events;
using System.Collections.Generic;
using DXTools.UI.Modules.Statistics.Model;
using DXTools.UI.Modules.Statistics.DataProviders;
using DXTools.UI.Core.ViewModel;
using DXTools.Core.CrmSdk;
using System.Collections.ObjectModel;

namespace DXTools.UI.Modules.Statistics.ViewModels
{
    public class EntitiesViewModel : ViewModelBase
    {
        private IDataProvider _dataProvider = null;
        private const string HEADER_INFO = "Entity Record Count";

        #region Properties

        private ObservableCollection<EntityStatistics> _entityList;
        public ObservableCollection<EntityStatistics> EntityList
        {
            get
            {
                return _entityList;
            }
            set
            {
                _entityList = value;
                RaisePropertyChanged("EntityList");
            }
        }

        private IOrderedEnumerable<EntityStatistics> _filteredEntityList;
        public IOrderedEnumerable<EntityStatistics> FilteredEntityList
        {
            get
            {
                return _filteredEntityList;
            }
            set
            {
                _filteredEntityList = value;
                RaisePropertyChanged("FilteredEntityList");
            }
        }

        private String _searchText;
        public String SearchText
        {
            get
            {
                return _searchText;
            }
            set
            {
                _searchText = value;
                RaisePropertyChanged("SearchText");
            }
        }

        public DelegateCommand<object> SearchCommand { get; private set; }

        #endregion

        #region Constructors

         public EntitiesViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer container)
            :base(regionManager,eventAggregator,container)
        {
            this.HeaderInfo = HEADER_INFO;
            
            this.CloseViewCommand = new DelegateCommand<object>(this.CloseView, this.CanCloseView);
            this.LoadEntitiesCommand = new DelegateCommand<object>(this.LoadEntities, this.CanLoadEntities);
            this.SearchCommand = new DelegateCommand<object>(this.Search, this.CanSearch);
            
            _dataProvider = new CRMDataProvider();

            RetrieveEntities();

        }

        
         #endregion

        #region Methods

        private void CloseView(object commandArg)
        {
            base.CloseView();
        }
        private bool CanCloseView(object commandArg)
        {
            return true;
        }

        private bool CanLoadEntities(object commandArg)
        {
            return true;
        }

        private bool CanLoadEntity(object commandArg)
        {
            return true;
        }

        private bool CanSearch(object commandArg)
        {
            return true;
        }
            
        #endregion

        #region Load Entities Command

        public DelegateCommand<object> LoadEntitiesCommand { get; private set; }
        public DelegateCommand<object> LoadEntityCommand { get; private set; }
        
        private void LoadEntities(object commandArg)
        {
            RetrieveEntities();

        }

        private void RetrieveEntities()
        {
            IsBusy = true;

            AsyncCallback asyncCallback = (result =>
            {
                IOrganizationService service = (IOrganizationService)result.AsyncState;
                ObservableCollection<EntityMetadata> data = (ObservableCollection<EntityMetadata>)service.EndExecute(result).Results[0].Value;
                
                Action method = () =>
                {
                    var entities = from a in data
                                   where a.IsValidForAdvancedFind == true
                                   orderby a.SchemaName
                                   select a;
                    
                    EntityList = new ObservableCollection<EntityStatistics>();
                    foreach(var item in entities)
                    {
                        if (item.DisplayName.UserLocalizedLabel != null)
                            EntityList.Add(new EntityStatistics() { Id = item.MetadataId, LogicalName = item.LogicalName, DisplayName= item.DisplayName.UserLocalizedLabel.Label, PrimaryIdAttribute = item.PrimaryIdAttribute, PrimaryNameAttribute = item.PrimaryNameAttribute });
                    }

                    LoadEntityListRecordCount();
                    
                    IsBusy = false;
                };

                this.View.Dispatcher.BeginInvoke(method);
            });

            this._dataProvider.RetrieveEntities(asyncCallback);
        }

        private void Search(object commandArg)
        {
            string text = Convert.ToString(commandArg);
            if (!String.IsNullOrEmpty(text))
                SearchText = text;

           LoadEntityListRecordCount();
        }

        private void LoadEntityListRecordCount()
        {
            IsBusy = true;
            
            Action method = () =>
            {
                int Total = 0;

                if (EntityList != null)
                {
                    var items = from a in EntityList
                                orderby a.DisplayName
                                select a;

                    if (!String.IsNullOrEmpty(SearchText))
                    {
                        items = from a in EntityList
                                where a.DisplayName.ToLower().Contains(SearchText.ToLower())
                                orderby a.DisplayName
                                select a;
                    }

                    FilteredEntityList = items;
                    Total = FilteredEntityList.Count<EntityStatistics>();

                    foreach (EntityStatistics item in FilteredEntityList)
                    {

                        //// Define the fetch attributes.
                        //// Set the number of records per page to retrieve.
                        //int fetchCount = 50000;
                        //// Initialize the page number.
                        //int pageNumber = 1;
                        //// Initialize the number of records.
                        //int recordCount = 0;
                        //// Specify the current paging cookie. For retrieving the first page, 
                        //// pagingCookie should be null.
                        //string pagingCookie = null;


                        RetrieveEntityTotals(item, 50000, 1 );
                        
                        
                    }

                }

                this.HeaderInfo = string.Format("{0} ({1})", HEADER_INFO, Total);
                

            };

            this.View.Dispatcher.BeginInvoke(method);
        }

        private void RetrieveEntityTotals(EntityStatistics Entity, int FetchTotal, int PageNumber)
        {
            AsyncCallback asyncCallback = (result =>
            {
                try
                {

                    IOrganizationService service = (IOrganizationService)result.AsyncState;
                    EntityCollection col = service.EndRetrieveMultiple(result);
                    int totalRecords = col.Entities.Count;
                   
                   
                    ObservableCollection<Entity> data = col.Entities;

                    Action methodCount = () =>
                    {
                        //foreach (Entity e in data)
                        //{
                        //    //Int32 aggregate = (Int32)((AliasedValue)e["recordcount"]).Value;
                        //    //FilteredEntityList.Single<EntityStatistics>(x => x.LogicalName == e.LogicalName).RecordCount += aggregate;
                        //    FilteredEntityList.Single<EntityStatistics>(x => x.LogicalName == e.LogicalName).RecordCount = totalRecords;

                        FilteredEntityList.Single<EntityStatistics>(x => x.LogicalName == col.EntityName).RecordCount += totalRecords;

                        if (col.MoreRecords)
                            RetrieveEntityTotals(Entity, FetchTotal, PageNumber + 1);
                        
                       
                        IsBusy = false;
                    };

                    this.View.Dispatcher.BeginInvoke(methodCount);

                }
                catch (Exception ex)
                {
                    string x = ex.Message;

                }

            });


            _dataProvider.RetrieveEntityRecordCount(Entity.LogicalName, Entity.PrimaryIdAttribute, FetchTotal, PageNumber, asyncCallback);
        }

        
       
        #endregion

    }
}
